using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using TechHeadBrothers.IO;
using TechHeadBrothers.Portal.Web.SilverlightStreaming.Commands;

namespace TechHeadBrothers.Portal.Web.SilverlightStreaming
{
    public class SilverlightStreamingManager
    {
        #region Properties

        private static readonly string manifestContent =
            @"<SilverlightApp>
                <source>dummy.xaml</source>
              </SilverlightApp>";

        private static readonly string manifestFilename = "manifest.xml";
        private static readonly string serviceRoot = "https://silverlight.services.live.com";

        private readonly string accountID;
        private readonly string accountKey;

        public string AccountID
        {
            get { return accountID; }
        }

        public string AccountKey
        {
            get { return accountKey; }
        }

        public string ServiceRoot
        {
            get { return serviceRoot; }
        }

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="SilverlightStreamingManager"/> class.
        /// </summary>
        /// <param name="accountID">The account ID.</param>
        /// <param name="accountKey">The account key.</param>
        public SilverlightStreamingManager(string accountID, string accountKey)
        {
            this.accountID = accountID;
            this.accountKey = accountKey;
        }

        /// <summary>
        /// Adds the file set.
        /// </summary>
        /// <param name="filename">The filename.</param>
        /// <param name="filesetName">Name of the file set.</param>
        /// <returns></returns>
        public bool AddFileSet(string filename, string filesetName)
        {
            if (string.IsNullOrEmpty(filename)) throw new ArgumentNullException("filename");
            if (string.IsNullOrEmpty(filesetName)) throw new ArgumentNullException("filesetName");
            if (!filename.EndsWith(".zip")) throw new ApplicationException("filename must be the path of a zip file");

            HttpWebRequest req = new AddFilesetCommand(this).GetRESTHttpWebRequest(filesetName);

            byte[] data = ReadBytes(filename);

            req.ContentLength = data.Length;

            using (Stream requestStream = req.GetRequestStream())
                requestStream.Write(data, 0, data.Length);

            HttpWebResponse resp = (HttpWebResponse) req.GetResponse();

            return resp.StatusCode == HttpStatusCode.OK;
        }

        /// <summary>
        /// Uploads the video. Hosting as content without application.
        /// </summary>
        /// <see cref="http://dev.live.com/silverlight/initparams.aspx"/>
        /// <param name="videoFilename">The filename.</param>
        /// <param name="filesetName">Name of the fileset.</param>
        /// <returns></returns>
        public bool UploadVideo(string videoFilename, string filesetName)
        {
            if (string.IsNullOrEmpty(videoFilename)) throw new ArgumentNullException("videoFilename");
            if (string.IsNullOrEmpty(filesetName)) throw new ArgumentNullException("filesetName");
            if (!videoFilename.EndsWith(".wmv")) throw new ApplicationException("filename must be the path of a wmv file");

            string zipFilename = videoFilename.Replace(".wmv", ".zip");

            CreateZipFile(videoFilename, zipFilename);

            return AddFileSet(zipFilename, filesetName);
        }

        /// <summary>
        /// Deletes the file set.
        /// </summary>
        /// <param name="filesetName">Name of the file set.</param>
        /// <returns></returns>
        public bool DeleteFileset(string filesetName)
        {
            HttpWebRequest req = new DeleteFilesetCommand(this).GetRESTHttpWebRequest(filesetName);

            HttpWebResponse resp = (HttpWebResponse) req.GetResponse();

            return resp.StatusCode == HttpStatusCode.OK;
        }

        /// <summary>
        /// Gets the file set files.
        /// </summary>
        /// <param name="fileSetName">Name of the file set.</param>
        /// <returns></returns>
        public List<string> GetFilesetFilesList(string fileSetName)
        {
            HttpWebRequest req = new GetFilesetFilesListCommand(this).GetRESTHttpWebRequest(fileSetName);

            HttpWebResponse resp = (HttpWebResponse) req.GetResponse();

            if (resp.StatusCode == HttpStatusCode.OK)
            {
                throw new ApplicationException("NOT YET IMPLEMENTED!!!");
            }

            return null;
        }

        /// <summary>
        /// Creates the zip file.
        /// </summary>
        /// <param name="videoPath">The video path.</param>
        /// <param name="zipPath">The zip path.</param>
        /// <returns></returns>
        public static void CreateZipFile(string videoPath, string zipPath)
        {
            string manifestPath = SaveManifest(videoPath);

            List<string> files = new List<string>(2);
            files.Add(videoPath);
            files.Add(manifestPath);

            ZipUtilities.SaveZip(files, zipPath, 1);
        }

        /// <summary>
        /// Saves the manifest.
        /// </summary>
        /// <param name="videoPath">The video path.</param>
        /// <returns></returns>
        public static string SaveManifest(string videoPath)
        {
            string manifestPath = Path.Combine(Path.GetDirectoryName(videoPath), manifestFilename);

            using (StreamWriter sw = File.CreateText(manifestPath))
                sw.Write(manifestContent);

            return manifestPath;
        }

        /// <summary>
        /// Reads the bytes.
        /// </summary>
        /// <param name="filename">The filename.</param>
        /// <returns></returns>
        protected static byte[] ReadBytes(string filename)
        {
            FileInfo fileInfo = new FileInfo(filename);

            FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);

            BinaryReader reader = new BinaryReader(fileStream);

            byte[] data = reader.ReadBytes((int) fileInfo.Length);
            reader.Close();

            return data;
        }
    }
}